﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Razor;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.FileProviders;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using Microsoft.IdentityModel.Tokens;
using Microsoft.Net.Http.Headers;
using StaticFilesSample.Infrastructure;
using StaticFilesSample.Middlewares;
using StaticFilesSample.Models;

namespace StaticFilesSample
{
    public class Startup
    {
        public Startup(IConfiguration configuration)
        {
            Configuration = configuration;
        }

        public IConfiguration Configuration { get; }

        // This method gets called by the runtime. Use this method to add services to the container.
        public void ConfigureServices(IServiceCollection services)
        {
            var physicalProvider = new PhysicalFileProvider(Directory.GetCurrentDirectory());
            var embeddedProvider = new EmbeddedFileProvider(Assembly.GetEntryAssembly());
            var compositeProvider = new CompositeFileProvider(physicalProvider, embeddedProvider);

            //services.AddSingleton<IFileProvider>(sp => physicalProvider);
            //services.AddSingleton<IFileProvider>(sp => embeddedProvider);
            services.AddSingleton<IFileProvider>(sp => compositeProvider);

            services.AddScoped<IBlogService, BlogService>();
            services.Configure<RazorViewEngineOptions>(opt =>
            {
                var fileProvider = new EmbeddedFileProvider(typeof(BlogService).GetTypeInfo().Assembly);
                opt.FileProviders.Add(fileProvider);
            });

            services.Configure<JwtSettings>(Configuration.GetSection("JwtSettings"));
            var jwtSettings = new JwtSettings();
            Configuration.Bind("JwtSettings", jwtSettings);

            services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
                .AddJwtBearer(opt =>
            {
                //opt.TokenValidationParameters = new Microsoft.IdentityModel.Tokens.TokenValidationParameters()
                //{
                //    ValidateIssuer = true,
                //    ValidateAudience = true,
                //    ValidIssuer = jwtSettings.Issuer,
                //    ValidAudience = jwtSettings.Audience,
                //    IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(jwtSettings.SecretKey))
                //};
                opt.SecurityTokenValidators.Clear();
                opt.SecurityTokenValidators.Add(new CustomSecurityTokenValidator());
                opt.Events = new JwtBearerEvents()
                {
                    OnMessageReceived = ctx =>
                     {
                         var token = ctx.Request.Headers["token"].FirstOrDefault();
                         ctx.Token = token;
                         return Task.CompletedTask;
                     }
                };
            });

            services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1);
        }

        // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
        public void Configure(IApplicationBuilder app, IHostingEnvironment env)
        {
            //app.UseWelcomePage();
            if (env.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();
            }
            app.UseExceptionHandler("/default/error");

            var provider = new PhysicalFileProvider(Path.Combine(env.ContentRootPath, "OutputStaticFiles"));
            var compositeProvider = new CompositeFileProvider(env.WebRootFileProvider, provider);

            env.WebRootFileProvider = compositeProvider;

            //var fileServerOpt = new FileServerOptions()
            //{
            //    FileProvider = provider,
            //};
            //fileServerOpt.DefaultFilesOptions.DefaultFileNames = new string[]{"default.html"};
            //app.UseFileServer(fileServerOpt);
            app.UseDefaultFiles(new DefaultFilesOptions()
            {
                FileProvider = provider,
                DefaultFileNames = new string[] { "default.html" }
            });
            app.UseStaticFiles(new StaticFileOptions()
            {
                FileProvider = provider,
            });
            app.UseDirectoryBrowser();

            //env.WebRootFileProvider = new PhysicalFileProvider();

            //var staticFileProvider = new PhysicalFileProvider(Path.Combine(env.ContentRootPath, "OutputStaticFiles"));
            //app.UseStaticFiles(new StaticFileOptions()
            //{
            //    FileProvider = staticFileProvider,
            //    RequestPath = "/OutputFiles",
            //    OnPrepareResponse = ctx =>
            //    {
            //        //ctx.Context.Response.Headers.Add(HeaderNames.CacheControl, $"max-age={60}");
            //        //ctx.Context.Response.Headers[HeaderNames.CacheControl] = $"max-age={60}";
            //        var headers = ctx.Context.Response.GetTypedHeaders();
            //        headers.CacheControl = new CacheControlHeaderValue()
            //        {
            //            MaxAge = TimeSpan.FromSeconds(60)
            //        };
            //    }
            //});

            app.Map(new PathString("/version"), builder =>
            {
            //builder.Use(async (ctx, next) =>
            //{
            //    Console.WriteLine("Version:1.0");
            //    await ctx.Response.WriteAsync("Version:1.0");
            //});
            builder.Run(async ctx =>
        {
                    Console.WriteLine("Version:1.0");
                    await ctx.Response.WriteAsync("Version:1.0");
                });
            });
            //app.UseWhen(context =>
            //{
            //    return context.Request.Method.Equals("get",StringComparison.OrdinalIgnoreCase);
            //}, builder =>
            //{
            //    builder.Use(async (ctx, next) =>
            //    {
            //        if (!ctx.Request.Query.ContainsKey("r"))
            //        {
            //            var versionStr = $"r={Guid.NewGuid().ToString("N")}";
            //            var queryStr = string.IsNullOrEmpty(ctx.Request.QueryString.Value) ? $"?{versionStr}" : $"{ctx.Request.QueryString.Value}&{versionStr}";
            //            ctx.Response.Redirect($"{ctx.Request.Path}{queryStr}");
            //        }
            //        await next();
            //    });
            //});
            //app.UseMiddleware<RequestRecordMiddleware>();
            //app.Use(async (ctx, next) =>
            //{
            //    Console.WriteLine("A Before.");
            //    await next();
            //    Console.WriteLine("A After.");
            //});
            //app.Use(async (ctx, next) =>
            //{
            //    Console.WriteLine("B Before.");
            //    await next();
            //    Console.WriteLine("B After.");
            //});
            //app.Run(async ctx =>
            //{
            //    Console.WriteLine("C");
            //    await ctx.Response.WriteAsync("Hello");
            //});
            //app.UseStatusCodePages("text/html","<h1>{0}</h1>");
            //app.UseStatusCodePagesWithRedirects("errorpage");
            app.UseStatusCodePagesWithReExecute("/errorpage", "?code={0}");
            app.UseAuthentication();
            app.UseMvcWithDefaultRoute();
        }
    }
}
